/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#include "stdafx.h"
#include <pgl/core/PGLStackedLine2D.h>
#include <pgl/core/DataRegistry.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

PGL_IMPLEMENT_DYNCREATE(CPGLStackedLine2D, CPGLObject);

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

//! Save settings
void CPGLStackedLine2D::SerializeXML(CPGLArchive& ar)
{
	static const TCHAR szTag[] = _T("CPGLStackedLine2D");
	std::_tstring str;
	CPGLLine1DPtr pLine;
	CString strPos;	strPos.Format(_T("%u"),(DWORD)this);

	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());
	if(ar.IsStoring())
	{
		ASSERT(m_pX);
		xml.AddChildElem(szTag);
		xml.AddChildAttrib(_T("Name"),GetName());
		xml.IntoElem();

			/////////////////////////////////////////////////////////
			// Adding base class
			CPGLObject::SerializeXML(ar);
			
			xml.AddChildElem(_T("Data"));
			xml.IntoElem();
				
				xml.AddChildElem(_T("X"));
				xml.IntoElem();
					m_pX->SerializeXML(ar);
				xml.OutOfElem();

				xml.AddChildElem(_T("Lines"));
				xml.IntoElem();
					// savings lines
					CPGLLine1DList::iterator il;
					for (il= m_lLines.begin(); il!= m_lLines.end();il++)
					{
						pLine = *il;
						if (!pLine)
							continue;
						
						pLine->SerializeXML(ar);
					}
				xml.OutOfElem();
			xml.OutOfElem();
			
		xml.OutOfElem();
	}
	else
	{
		if  (!xml.FindChildElem(szTag))
				return;
		Clear();

		xml.IntoElem();
			/////////////////////////////////////////////////////////
			// Adding base class
			CPGLObject::SerializeXML(ar);

			if (xml.FindChildElem(_T("Data")))
			{
				xml.IntoElem();
					PGL_SERIALIZE_LOAD_DATA( strPos , X , m_pX );

					xml.ResetChildPos();
					if (xml.FindChildElem(_T("Lines")))
					{
						xml.IntoElem();
							// saving position
							xml.SavePos(strPos);
							while (xml.FindChildElem(_T("CPGLLine1D")))
							{
								pLine = CPGLLine1DPtr(new CPGLLine1D);	

								xml.RestorePos(strPos);
								pLine->SerializeXML(ar);
								PushTop(pLine);

								// saving position
								xml.SavePos(strPos);
							}
						xml.OutOfElem();
					}
				xml.OutOfElem();
			}
		xml.OutOfElem();
	}
}


#ifdef _DEBUG
void CPGLStackedLine2D::Dump( CDumpContext& dc ) const
{
    // call base class function first
    CPGLObject::Dump( dc );

    // now do the stuff for our specific class
	dc << _T("CPGLStackedLine2D ID ") << GetID() << "\n";
}
void CPGLStackedLine2D::AssertValid() const
{
    // call inherited AssertValid first
    CPGLObject::AssertValid();

    // check members...
} 
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPGLStackedLine2D::CPGLStackedLine2D(const CPGLColor& _color)
: CPGLObject(_color)
{
	m_pYSum = CPGLVectorFPtr(new CPGLVectorF);
}

CPGLStackedLine2D& CPGLStackedLine2D::operator = (const CPGLStackedLine2D& r)
{
	if (this!=&r)
	{
		this->CPGLObject::operator =(r);

		Clear();
		m_pX = r.m_pX->Clone();

		CPGLLine1DList::const_iterator il;
		for (il = r.m_lLines.begin(); il != r.m_lLines.end(); il++)
		{
			if (!*il)
				continue;

			CPGLLine1DPtr pLine( boost::shared_polymorphic_cast<CPGLLine1D, CPGLNode> ((*il)->MakeCopy()) ); 
			m_lLines.push_back(pLine);
		}
	}
	return *this;
}

void CPGLStackedLine2D::Clear()
{
	m_pX.reset();
	m_lLines.clear();
}

void CPGLStackedLine2D::PushBottom(CPGLLine1DPtr pLine1D)
{	
	if (!pLine1D)
		return;

	m_lLines.push_front(pLine1D); 
	pLine1D->SetFilled(true); 
	pLine1D->SetSnapBottom(true);
};

void CPGLStackedLine2D::PushTop(CPGLLine1DPtr pLine1D)
{	
	if (!pLine1D)
		return;
	
	m_lLines.push_back(pLine1D);  
	pLine1D->SetFilled(true); 
	pLine1D->SetSnapBottom(true);
};

void CPGLStackedLine2D::GetUnionExtent(gfxinterface::CGfxInterface& gfx, CPGLRectD& rExtent)
{
	CPGLObject::GetUnionExtent(gfx, rExtent);

	GetExtent().SetUnion(rExtent);

	if (m_lLines.empty())
	{
		rExtent.xValid=false;
		rExtent.yValid=false;
	}
	else
	{
		rExtent.xValid=true;
		rExtent.yValid=true;
	}
}

void CPGLStackedLine2D::SetX(const std::vector<double>& vX)
{
	m_pX = CPGLVectorDPtr(new CPGLVectorD(vX));
}

void CPGLStackedLine2D::SetX(const std::vector<float>& vX)
{
	m_pX = CPGLVectorFPtr(new CPGLVectorF(vX));
}

void CPGLStackedLine2D::UpdateExtent(gfxinterface::CGfxInterface& gfx)
{
	// Calling base class function
	CPGLObject::UpdateExtent(gfx);

	if (!m_pX || m_pX->size()==0 || m_lLines.size()==0)
		return;

	CPGLRectD rExtent;

	size_t i;
	std::vector<float> vY;
	CPGLLine1DPtr pLine;
	CPGLLine1DList::iterator il;
	
	UINT n = m_pX->size();

	il = m_lLines.begin();
	pLine=*il;
	il++;
	n=__min(n,pLine->GetValues()->size());

	vY.resize(n);
	rExtent.bottom= std::numeric_limits<float>::infinity();
	for (i=0; i<n;i++)
	{
		vY[i]=(float)pLine->GetValue(i);
		rExtent.bottom=__min( rExtent.bottom, vY[i]);
	}

	for (; il != m_lLines.end() ;il++)
	{
		pLine=*il;

		n=__min(n, pLine->GetValues()->size() );
		for (UINT i=0; i < n; i++)
		{
			vY[i]+=(float)pLine->GetValue(i);
		}
	}

	rExtent.left=(*m_pX)[0];
	rExtent.right=rExtent.left;
	rExtent.top=rExtent.bottom;
	for (i=0; i<n;i++)
	{
		rExtent.left=__min( rExtent.left, (*m_pX)[i]);
		rExtent.right=__max( rExtent.right, (*m_pX)[i]);
		rExtent.top=__max( rExtent.top, vY[i]);
	}

	SetExtent(rExtent);
}

void CPGLStackedLine2D::PlotGfx(gfxinterface::CGfxInterface& gfx)
{
	if (!IsVisible())
		return;
	if (!IsInLayer(gfx.GetLayer()))
		return;
	if (!m_pX)
		return;
	if (m_lLines.empty())
		return;

	CPGLLine1DPtr pLine;
	CPGLLine1DList::iterator il;
	UINT i;
	DWORD type;
	UINT nx=m_pX->size();

	// first line...
	il = m_lLines.begin();
	pLine=*il;
	il++;
	// setting color and fill...
	pLine->CPGLObject::PlotGfx(gfx);
	pLine->SetDashGfx(gfx);	
	// set line width
	gfx.SetLineWidth(pLine->GetLineWidth());	

	ASSERT(m_pYSum);
	std::vector<float>& v=m_pYSum->GetV();
	v.resize(pLine->GetValues()->size());
	for (i=0;i<pLine->GetValues()->size();i++)
		v[i]=(float)pLine->GetValue(i);

	gfx.DrawLineStrip( *m_pX, *m_pYSum, pLine->GetELineType());

	// drawing...
	for ( ; il != m_lLines.end() ;il++)
	{
		pLine=*il;

		gfx.PushState();

			// set color...
			pLine->CPGLObject::PlotGfx(gfx);
			// setting color and fill...
			pLine->SetDashGfx(gfx);	
			// set line width
			gfx.SetLineWidth(pLine->GetLineWidth());
			type = ProcessType(pLine->GetELineType());
			gfx.DrawBandStrip(*m_pX,*m_pYSum,*pLine->GetValues(),type, pLine->GetTension());
			// update vYSum...
			for (i=0;i<pLine->GetValues()->size();i++)
				v[i]+=(float)pLine->GetValue(i);
	
		gfx.PopState();

		if (pLine->GetMarker())
			pLine->GetMarker()->PlotGfx(gfx, m_pX, m_pYSum);
	}
}

DWORD CPGLStackedLine2D::ProcessType(DWORD eLineType)
{
	using namespace gfxinterface;

	DWORD lt;

	if (eLineType & LineTypeNoContour)
		lt=gfxinterface::BandTypeNoContour;
	else
		lt=0;

	if ( eLineType & LineTypeClosed )
		lt |= gfxinterface::BandTypeFullContour;
	if (!(eLineType &LineTypeFilled))
		lt |= gfxinterface::BandTypeNotFilled;
	if (eLineType &LineTypeShadow)
		lt |= gfxinterface::BandTypeLineShadow;

	return lt;
}

void CPGLStackedLine2D::PushLinesTop(CPGLLegendPtr pLegend)
{
	if (! pLegend)
		return;

	CPGLLine1DList::iterator il;
	for (il = m_lLines.begin(); il != m_lLines.end(); il++)
	{
		if (!(*il))
			continue;

		pLegend->PushTop( *il);
	}
}

void CPGLStackedLine2D::SetX(CPGLDataPtr pX)
{
	m_pX = pX;
}

/*
CPGLObject* CPGLStackedLine2D::FindObjectID(UINT _ID)
{
	CPGLObject* pObject=NULL;
	
	CPGLLine1DList::iterator il;
	for (il = m_lLines.begin(); il != m_lLines.end(); il++)
	{
		pObject=(*il)->FindObjectID(_ID);
		if (pObject)
			return pObject;
	}

	return CPGLObject::FindObjectID(_ID);
}
*/
